package com.x.chalk.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.x.chalk.config.RedisKeyConfig;
import com.x.chalk.config.SystemConfig;
import com.x.chalk.dao.ScorelogDao;
import com.x.chalk.dao.SignTaskDao;
import com.x.chalk.dao.UserDao;
import com.x.chalk.dao.UserlogDao;
import com.x.chalk.dto.UserAddDto;
import com.x.chalk.dto.UserLoginCodeDto;
import com.x.chalk.dto.UserLoginDto;
import com.x.chalk.dto.UserUpdateDto;
import com.x.chalk.entity.Scorelog;
import com.x.chalk.entity.SignTask;
import com.x.chalk.entity.User;
import com.x.chalk.entity.Userlog;
import com.x.chalk.service.intf.UserService;
import com.x.chalk.util.JedisUtil;
import com.x.chalk.util.PassUtils;
import com.x.chalk.vo.R;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.sql.SQLException;

/**
 * ━━━━━━神兽出没━━━━━━
 * 　　　┏┓　　　┏┓
 * 　　┏┛┻━━━┛┻┓
 * 　　┃　　　　　　 ┃
 * 　　┃　　　━　　　┃
 * 　　┃　┳┛　┗┳　  ┃
 * 　　┃　　　　　　 ┃
 * 　　┃　　　┻　　　┃
 * 　　┃　　　　　　　┃
 * 　　┗━┓　　　┏━┛Code is far away from bug with the animal protecting
 * 　　　　┃　　　┃    神兽保佑,代码无bug
 * 　　　　┃　　　┃
 * 　　　　┃　　　┗━━━┓
 * 　　　　┃　　　　　　　┣┓
 * 　　　　┃　　　　　　　┏┛
 * 　　　　┗┓┓┏━┳┓┏┛
 * 　　　　　┃┫┫　┃┫┫
 * 　　　　　┗┻┛　┗┻┛
 * ━━━━━━永无BUG!━━━━━━
 *
 * @Description:
 * @Author: 邢朋辉
 * @Date: 2022/9/14 14:27
 */
@Service
public class UserServiceImpl implements UserService {
    //修饰dao层的变量
    private final UserDao dao;
    private final UserlogDao logDao;
    private final ScorelogDao scorelogDao;
    private final SignTaskDao signTaskDao;

    public UserServiceImpl(UserDao dao, UserlogDao logDao, ScorelogDao scorelogDao, SignTaskDao signTaskDao) {
        this.dao = dao;
        this.logDao = logDao;
        this.scorelogDao = scorelogDao;
        this.signTaskDao = signTaskDao;
    }

    @Override
    public R update(UserUpdateDto dto,String token) {
        if (dto!=null){
            if (dto.getPhone()!=null){
                long uid= Long.parseLong(token);
                User user = dao.selectOne(new QueryWrapper<User>().eq("id", uid));
                user.setPhone(dto.getPhone());
                dao.updateById(user);
                return R.ok();
            }
            if (dto.getName()!=null){
                long uid= Long.parseLong(token);
                User user = dao.selectOne(new QueryWrapper<User>().eq("id", uid));
                user.setName(dto.getName());
                dao.updateById(user);
                return R.ok();
            }
            if (dto.getPassword()!=null){
                long uid= Long.parseLong(token);
                User user = dao.selectOne(new QueryWrapper<User>().eq("id", uid));
                user.setPassword(dto.getPassword());
                dao.updateById(user);
                return R.ok();
            }else {
                return R.fail();
            }
        } else {
            return R.fail();
        }
    }

    @Override
    public R del(String token) {
        if (StringUtils.hasLength(token)) {
            long uid = Long.parseLong(token);
            dao.deleteById(uid);
            return R.ok();
        }else {
            return R.fail();
        }
    }

    /**
     * 实现用户注册
     * 开启事务*/
    @Override
    @Transactional(rollbackFor = SQLException.class)
    public R register(UserAddDto dto, String ip) {
        //1.入参校验
        if (dto != null) {
            //2.校验内容是否非空
            if (StringUtils.hasLength(dto.getPhone()) && StringUtils.hasLength(dto.getPassword())) {

                //防止直接请求接口
                //3.查询用户
                User user = getUser(dto.getPhone());
                //4.验证手机号是否存在
                if (user == null) {

                    //如何保证验证码测试通过，才可以注册用户？
                    //5.校验是否通过了手机验证码的校验，通过看才可以注册
                    if (JedisUtil.existsSet(RedisKeyConfig.USER_ADDPHONES, dto.getPhone())) {

                        //6.设置要注册的用户
                        user = new User(dto.getPhone(), PassUtils.aesenc(SystemConfig.PASS_KEY, dto.getPassword()));
                        //7.验证操作数据库是否成功
                        if (dao.insert(user) > 0) {

                            //8.新增成功,删除之前记录的手机号
                            JedisUtil.delSet(RedisKeyConfig.USER_ADDPHONES, dto.getPhone());

                            //10 记录日志
                            logDao.insert(new Userlog(user.getId(), 1, "用户完成注册", ip));

                            signTaskDao.insert(new SignTask(user.getId(),1,"阅读文章",1,1));
                            signTaskDao.insert(new SignTask(user.getId(),1,"看经验贴",1,2));
                            signTaskDao.insert(new SignTask(user.getId(),2,"发布帖子",1,3));
                            signTaskDao.insert(new SignTask(user.getId(),1,"发布评论",1,4));
                            signTaskDao.insert(new SignTask(user.getId(),1,"转发帖子",1,5));
                            return R.ok(null);
                        }
                    }
                }
            }
        }
        return R.fail();
    }

    /**校验手机号是否存在*/
    @Override
    public R checkPhone(String phone) {
        //1.入参校验
        if (StringUtils.hasLength(phone)) {
            //2.正则校验
            if (phone.matches(SystemConfig.PHONE_RX)) {

                //3.查询数据库
                User user =getUser(phone);

                //4.验证数据库是否存在
                if (user == null) {
                    //不存在，可用
                    return R.ok(null);
                }
            }
        }
        return R.fail();
    }

    @Override
    public R all() {
        return R.ok(dao.selectList(null));
    }

    /**
     *唯一登录：一个账号，只能在线1个 */
    @Override
    public R loginPassword(UserLoginDto dto, String ip) {
        //手机号密码登录
        //1.校验
        if (dto != null) {
            if (StringUtils.hasLength(dto.getPhone())) {
                //2.查询数据库
                User user = getUser(dto.getPhone());
                //3.验证是否存在用户
                if (user != null) {

                    //4.验证账号是否有效
                    if (user.getFlag() == SystemConfig.USER_OK) {

                        //5.验证密码
                        if (user.getPassword().equals(PassUtils.aesenc(SystemConfig.PASS_KEY, dto.getPassword()))) {
                            //6.账号 密码正确 生成令牌 存储并返回
                            return createToken(dto.getPhone(), user.getId(), "账号密码", ip);
                        }
                    }
                }
            }
        }
        return R.fail("亲，账号或密码不正确！");
    }
    /**
     *选择：手机号验证码登录，另一种：如果手机号不存在，自动注册，在自动登录 */
    @Override
    public R loginCode(UserLoginCodeDto dto, String ip) {
        //手机号验证码登录
        //1.校验
        if (dto != null) {
            User user = getUser(dto.getPhone());
            //3.验证是否存在用户
            if (user != null) {

                //4.验证账号是否有效
                if (user.getFlag() == SystemConfig.USER_OK) {
                    if (JedisUtil.exists(RedisKeyConfig.USER_LOGINCODE + dto.getPhone())) {

                        //5.验证 对应的验证码
                        if (JedisUtil.getString(RedisKeyConfig.USER_LOGINCODE + dto.getPhone()).equals(dto.getCode())) {
                            //删除验证码
                            JedisUtil.delKey(RedisKeyConfig.USER_LOGINCODE + dto.getPhone());
                            //6.账号 密码正确 生成令牌 存储并返回
                            return createToken(dto.getPhone(), user.getId(), "手机号验证码", ip);
                        }
                    }
                }
            }
        }
        return R.fail("亲，手机号或验证码不正确！");
    }

    /**
     * 1.查询用户
     */
    private User getUser(String phone) {
        //1.校验
        if (StringUtils.hasLength(phone)) {

            //2.查询数据库
            QueryWrapper<User> wrapper = new QueryWrapper<>();
            wrapper.eq("phone", phone);

            //3.返回查询到的用户
            return dao.selectOne(wrapper);
        }
        return null;
    }

    /**2.实现登录的令牌存储*/
    private R createToken(String phone, long uid, String msg, String ip) {
        //1.验证当前账号是否已经在线
        if (JedisUtil.exists(RedisKeyConfig.USER_PHONE + phone)) {
            //2.如果存在，唯一登录，挤掉信息 存储 Redis
            JedisUtil.addHash(RedisKeyConfig.USER_LOGIN_DROP, phone, "亲。你在其他设备已登录！");
            //调用极光推送的Api 实现消息推送  省略
        }
        //3.生成令牌  简单的形式，直接使用 用户id
        String token = uid + "";
        //4.存储令牌 到Redis中
        //Redis:1.为什么使用  2.有没有有效期 3.什么数据类型 4.存储什么数据
        JedisUtil.addString(RedisKeyConfig.USER_PHONE + phone, token, RedisKeyConfig.USER_PHONE_TIME);

        //5.验证是否每日首次登录
        if (logDao.selectLoginlog(uid) == null) {

            //7.记录积分变动流水
            scorelogDao.insert(new Scorelog(uid, 1, 10, "每日首次登录，奖励10积分"));
        }

        //8.记录用户登录日志
        logDao.insert(new Userlog(uid, 2, "用户通过" + msg + "登录成功", ip));

        return R.ok(token);
    }

    @Override
    public R loginOut(String phone) {
        //1.校验参数
        if (StringUtils.hasLength(phone)) {
            //2.校验当前手机号 是否在线
            if (JedisUtil.exists(RedisKeyConfig.USER_PHONE + phone)) {
                //3.退出登录
                JedisUtil.delKey(RedisKeyConfig.USER_PHONE + phone);
                return R.ok();
            }
        }
        return R.fail("亲，你都没有登录！");
    }

    @Override
    public R checkToken(String phone) {
        //1.校验参数
        if (StringUtils.hasLength(phone)) {
            //2.验证是存在挤掉信息
            if (JedisUtil.existsHash(RedisKeyConfig.USER_LOGIN_DROP, phone)) {
                //你被挤掉了
                JedisUtil.delHash(RedisKeyConfig.USER_LOGIN_DROP, phone);
                return R.ok("亲，你被挤掉了！");
            }
        }
        return R.fail();
    }

    //签到添加积分
    @Override
    public R updateScore(String token, Integer score) {
        return R.ok(dao.updateScore(Long.parseLong(token),score));
    }

    @Override
    public R selectScoreById(String token) {
        return R.ok(dao.selectById(Long.parseLong(token)).getScore());
    }
}
